package ru.spb.osll.myfit.server.fixtureiterator;

import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.junit.Assert.assertTrue;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.collections.iterators.IteratorEnumeration;
import org.easymock.EasyMockSupport;
import org.junit.Before;
import org.junit.Test;

import ru.spb.osll.myfit.fixtures.base.DummyOneLineFixture;
import ru.spb.osll.myfit.fixtures.base.OneLineFixture;
import ru.spb.osll.myfit.util.CollectionUtils;

public class ClasspathIteratorTest extends EasyMockSupport {
	private class DummyFixtureIteratorListener implements
			FixtureIteratorListener {
		public String m_fixtures = ":";

		@Override
		public void listen(Class<?> clazz) {
			m_fixtures = m_fixtures + clazz.getSimpleName() + ":";
		}

	}

	private URLClassLoader classLoader;
	private FileFactory fileFactory;
	private ClasspathIterator iterator;
	private DummyFixtureIteratorListener listener;
	private JarFile jar;

	@Before
	public void setUp() {
		classLoader = createStrictMock(URLClassLoader.class);
		fileFactory = createStrictMock(FileFactory.class);
		jar = createStrictMock(JarFile.class);

		listener = new DummyFixtureIteratorListener();
	}

	@Test
	public void testIterateDir() throws Exception {
		URL url = new URL("file", "localhost", "lib");
		iterator = new ClasspathIterator(classLoader, fileFactory, new URL[] { url });
		FileDummy file = new FileDummy("lib");
		file.add("lib/OneLineFixture.class", "lib/DummyOneLineFixture.class");
		expect(fileFactory.createFile("lib")).andReturn(file);

		classLoader.loadClass("OneLineFixture");
		expectLastCall().andReturn(OneLineFixture.class);
		classLoader.loadClass("DummyOneLineFixture");
		expectLastCall().andReturn(DummyOneLineFixture.class);

		replayAll();
		iterator.iterateFixtures(listener);
		verifyAll();
		assertTrue(listener.m_fixtures.contains("OneLineFixture"));
		assertTrue(listener.m_fixtures.contains("DummyOneLineFixture"));
	}

	@Test
	public void testIterateDirWithPackages() throws Exception {
		URL url = new URL("file", "localhost", "lib");
	  iterator = new ClasspathIterator(classLoader, fileFactory, new URL[] { url });
		FileDummy file = new FileDummy("lib");
		file.add("lib/ru").add("lib/ru/osll").add("lib/ru/osll/myfit").add(
				"lib/ru/osll/myfit/fixtures").add(
				"lib/ru/osll/myfit/fixtures/base").add(
				"lib/ru/osll/myfit/fixtures/base/OneLineFixture.class");
		expect(fileFactory.createFile("lib")).andReturn(file);
		classLoader.loadClass("ru.osll.myfit.fixtures.base.OneLineFixture");
		expectLastCall().andReturn(OneLineFixture.class);

		replayAll();
		iterator.iterateFixtures(listener);
		verifyAll();
		assertTrue(listener.m_fixtures.contains("OneLineFixture"));
	}

	@SuppressWarnings("unchecked")
	@Test
	public void testIterateJar() throws Exception {
		URL url = new URL("file", "localhost", "fixtures.jar");
    iterator = new ClasspathIterator(classLoader, fileFactory, new URL[] { url });
		FileDummy file = new FileDummy("fixtures.jar");
		expect(fileFactory.createFile("fixtures.jar")).andReturn(file);
		expect(fileFactory.createJar(file)).andReturn(jar);
		Enumeration<JarEntry> enumeration = (Enumeration<JarEntry>) new IteratorEnumeration(
				CollectionUtils
						.list(
								new JarEntry(
										"ru/osll/myfit/fixtures/base/OneLineFixture.class"))
						.iterator());
		expect(jar.entries()).andReturn(enumeration);
		classLoader.loadClass("ru.osll.myfit.fixtures.base.OneLineFixture");
		expectLastCall().andReturn(OneLineFixture.class);

		replayAll();
		iterator.iterateFixtures(listener);
		verifyAll();
		assertTrue(listener.m_fixtures.contains("OneLineFixture"));
	}
}
